package com.data1.common.core.aspectj;

import com.data1.common.core.annotation.Traceable;
import io.micrometer.tracing.Span;
import io.micrometer.tracing.Tracer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TraceAspect {

    @Autowired
    private Tracer tracer;

    @Around("@annotation(traceable)")
    public Object traceMethod(ProceedingJoinPoint joinPoint, Traceable traceable) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getMethod().getName();
        String className = signature.getDeclaringType().getSimpleName();

        String spanName = traceable.value().isEmpty() ?
            className + "." + methodName : traceable.value();

        Span span = tracer.nextSpan()
                .name(spanName)
                .start();

        try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
            span.tag("class", className);
            span.tag("method", methodName);

            // 根据配置决定是否添加方法参数信息
            if (traceable.logArgs()) {
                Object[] args = joinPoint.getArgs();
                for (int i = 0; i < args.length; i++) {
                    if (args[i] != null) {
                        span.tag("arg" + i, args[i].toString());
                    }
                }
            }

            Object result = joinPoint.proceed();

            // 根据配置决定是否添加返回值信息
            if (traceable.logResult() && result != null) {
                span.tag("returnType", result.getClass().getSimpleName());
            }

            return result;
        } catch (Exception ex) {
            span.tag("error", ex.getClass().getSimpleName() + ": " + ex.getMessage());
            throw ex;
        } finally {
            span.end();
        }
    }
}
